package cn.springcloud.provider.aop;


import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.log4j.Category;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Objects;

/**
 * 异常 AOP 处理
 */
@Aspect
@Component
@Slf4j
public class ExceptAop {

    private Exception e;

    private static final String ln = "\n" ;

    //凡是注解了RequestMapping的方法都被拦截
   /* @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    private void webPointcut() {
    }*/

    /*@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    private void postPointcut() {
    }*/


    //                  修饰符 包名 方法名 （参数名）
    @Pointcut("execution(* cn.springcloud.*.controller..*.*(..))")
    private void bountyHunterPointcut() {

    }

    /**
     * 前置通知
     * @param joinPoint
     */
//    @Before("bountyHunterPointcut()")
//    public void beforeLog(JoinPoint joinPoint){
//        System.out.println("我是前置通知:"+System.currentTimeMillis());
//    }

    /**
     * 环绕通知
     * @param joinPoint
     * @return
     */
    @Around("bountyHunterPointcut()")
    public Object testRunTime(ProceedingJoinPoint joinPoint){
        String target = joinPoint.getSignature().getDeclaringType()+"."+joinPoint.getSignature().getName() ;
        try {
            log.info("aop_target :[ "+ target + "] --- AOP around start");
            long startTimeMillis = System.currentTimeMillis();

            Object[] args = joinPoint.getArgs();
            for (Object obj:args) {
                System.err.println("接口方法参数："+obj);
            }

            //调用 proceed() 方法才会真正的执行实际被代理的方法
            Object result = joinPoint.proceed();
            //执行时间
            log.info("aop_target :[ "+ target + "] 执行时间: "+( System.currentTimeMillis() - startTimeMillis)+" ms " );
            //返回接口调用的结果
            return result;
        } catch (Throwable te) {
            log.error("环绕通知:"+te.getMessage(),te);
            throw new RuntimeException(te.getMessage());
        }
    }



    /**
     * 后置通知
     * @param joinPoint
     */
//    @After("bountyHunterPointcut()")
//    public void After(JoinPoint joinPoint){
//        System.out.println("我是后置通知:"+System.currentTimeMillis());
//    }





    /**
     * 拦截web层异常，记录异常日志，并返回友好信息到前端 目前只拦截Exception，是否要拦截Error需再做考虑
     *
     * @param e
     *            异常对象
     */
    @AfterThrowing(pointcut = "bountyHunterPointcut()", throwing = "e")
    public void handleThrowing(JoinPoint joinPoint,Exception e) {
        this.e = e;
        log.error("【"+joinPoint.getSignature().getDeclaringType()+"."+joinPoint.getSignature().getName()+Arrays.toString(joinPoint.getArgs())+"】--- 【抛出异常:" + e.getMessage()+"】");
        //友好性信息
        writeContent("出现异常" + e.getMessage());
    }

    /**
     * 将内容输出到浏览器
     *
     * @param content
     *            输出内容
     */
    private void writeContent(String content) {
        HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
        assert response != null;
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Type", "text/json;charset=UTF-8");
        response.setHeader("icop-content-type", "exception");
        PrintWriter writer = null;
        JsonGenerator jsonGenerator = null;
        try {
            writer = response.getWriter();
            jsonGenerator = (new ObjectMapper()).getFactory().createGenerator(writer);
            jsonGenerator.writeObject(content);
        } catch (IOException e1) {
            e1.printStackTrace();
        }finally {
            assert writer != null;
            writer.flush();
            writer.close();
        }
    }




}
